﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PSE.AuditLogging.Client.Configuration;
using System.Diagnostics;

namespace PSE.AuditLogging.ContingencyService
{
    internal class ServiceExecutor
    {
        private static object _syncRoot = new object();
        private static object _syncRootProduct = new object();
        private static ServiceExecutor _instance;

        private Dictionary<string, LogResender> _logResenders;//produto x logResender
        internal bool IsRunning
        {
            get;
            private set;
        }

        private ServiceExecutor()
        {
        }

        internal static ServiceExecutor GetInstance()
        {
            lock (_syncRoot)
            {
                if (_instance == null)
                    _instance = new ServiceExecutor();

                return _instance;
            }
        }

        #region Metodos de controle de execucao
        internal void Start()
        {
            lock (_syncRoot)
            {
                if (!this.IsRunning)
                {
                    _logResenders = new Dictionary<string, LogResender>();

                    //para cada produto configurado iniciar um logResender
                    foreach (LogSenderConfigurationSection config in ConfigurationReader.ContingencyServiceConfiguration.LogSenders)
                    {
                        StartProduct(config.ProductId);
                    }

                    this.IsRunning = true;
                }
            }
        }

        internal void Stop()
        {
            lock (_syncRoot)
            {
                if (this.IsRunning)
                {
                    //para cada produto configurado parar o logResender
                    foreach (LogSenderConfigurationSection config in ConfigurationReader.ContingencyServiceConfiguration.LogSenders)
                    {
                        StopProduct(config.ProductId);
                    }

                    this.IsRunning = false;
                }
            }
        }

        internal void Restart()
        {
            this.Stop();
            this.Start();
        }

        #endregion

        #region Metodos de controle de execucao por produto
        internal bool StartProduct(string productId)
        {
            bool started = true;
            lock (_syncRootProduct)
            {
                //se ja existe no dicionario de resenders
                if (_logResenders.ContainsKey(productId))
                {
                    if (!_logResenders[productId].Start())
                        started = false;
                }
                else
                {
                    LogResender resender = new LogResender(productId);
                    if (!resender.Start())
                        started = false;

                    _logResenders.Add(productId, resender);
                }
            }
            return started;
        }

        internal bool StopProduct(string productId)
        {
            bool stoped = true;
            lock (_syncRootProduct)
            {
                if (_logResenders.ContainsKey(productId))
                {
                    if (!_logResenders[productId].Stop())
                        stoped = false;

                    _logResenders.Remove(productId);
                }
            }

            return stoped;
        }

        internal bool RestartProduct(string productId)
        {
            bool ret = true;

            if (!this.StopProduct(productId))
                ret = false;

            if (!this.StartProduct(productId))
                ret = false;

            return ret;
        }

        internal List<string> GetRunningProducts()
        {
            List<string> ret = new List<string>();

            foreach (KeyValuePair<string, LogResender> item in _logResenders)
            {
                if (item.Value.IsRunning)
                    ret.Add(item.Key);
            }

            return ret;
        }
        #endregion

    }
}
